package com.atguigu.lease.admin.service.impl;

import com.atguigu.lease.admin.service.FileService;
import com.atguigu.lease.common.config.MinioConfig;
import com.atguigu.lease.common.util.FileType;
import com.atguigu.lease.common.util.FileUtil;
import io.minio.*;
import io.minio.errors.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.UUID;

@Service
public class FileServiceImpl implements FileService {
    /*
        分析：
            1、初始化minio客户端对象
            2、判断是否存在项目使用的桶，如果不存在创建(需要设置 public读 private写 权限)
            3、将文件上传到 minio指定桶内
            4、拼接文件在minio内的路径返回
        实现：
            1、检查minio依赖是否引入
            2、创建Minio客户端对象：
                    ioc容器中是否有minio对象？
                            -  容器中没有minio客户端对象
                                原因： 1、minio依赖没有自定义springboot自动配置文件(自定义springboot starter)
                                       2、sprigboot autoconfigure包自动配置文件 也没有Minio的自动配置类
                    redis启动器引入后，容器会自动创建StringRedisTemplate和RedisTemplate对象 注入到ioc容器
                            - 原理：自动配置
                                    redis启动器引入后 + spring autoconfigure包中自动配置文件包含了RedisAutoConfiguration自动配置类
                                    如果引入依赖中包含了自动配置类ConditionOnClass注解需要的类或 接口，那么springboot会自动创建这个配置类对象注入到容器中
            3、判断是否存在项目使用的桶，如果不存在创建
            4、上传文件，返回文件访问地址
         优化：
            1、硬编码问题
                配置字符串 一般不在业务代码中写死
            2、代码冗余问题
                Minio客户端对象 以后多个业务都可能使用
            3、对象重复创建问题：

                > IOC+DI： 控制反转-依赖注入
                    将minio对象 交给容器管理，以后可以从容器中装配使用
                    使用了同一个对象
                > 容器创建对象时，可以自动加载配置文件配置使用
            4、恶意文件上传问题：
                > 限制上传文件大小
                > 通过文件头判断文件格式
                    常见的文件真实格式的文件头是固定的

     */
    @Autowired
    MinioClient minioClient;
    @Autowired
    MinioConfig minioConfig;
    @Override
    public String upload(MultipartFile file) {
        try {
            //3、上传文件到桶内
            // 获取上传文件的 文件名称
            String filename = file.getOriginalFilename();
            // 生成唯一的文件名: 唯一字符串+ 原文件的扩展名
            // 20250623/1231421412414_qeqweq1.jpg
            //拼接桶内保存文件的目录路径+文件名
            String path =  new SimpleDateFormat("yyyyMMdd").format(new Date())+
                    "/"+ System.currentTimeMillis()+"_"+ UUID.randomUUID().toString().substring(0,6)
                    + filename.substring(filename.lastIndexOf("."));
            minioClient.putObject(PutObjectArgs.builder()  //putObject 通过文件流上传文件
                    //保存文件的桶
                    .bucket(minioConfig.getBucket())
                    //上传文件的文件流、流内容字节大小、分片大小(-1不分片)
                    .stream(file.getInputStream(),file.getInputStream().available(),-1)
                    //桶内文件的路径和名称
                    .object(path)
                    .build());

            //4、拼接上传成功的文件地址
            return minioConfig.getEndpoint()+"/"+ minioConfig.getBucket() +"/"+path;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

}
